package api

import (
	"fmt"
	"net/http"
	"strings"

	"rank/internal/api/docs"
	"rank/internal/assets"
	"rank/internal/status"
	"rank/internal/store"
	"rank/pkg/middleware"
	"rank/pkg/schema"

	"github.com/gin-gonic/gin"
	"github.com/rs/zerolog/log"
	ginSwagger "github.com/swaggo/gin-swagger"
	"github.com/swaggo/gin-swagger/swaggerFiles"
)

var _ Handler = (*restHandler)(nil)

type Handler interface {
	Init(svrName string) error
	RegisterHandler(engine *gin.Engine) error
}

func NewRestHandler(dao store.Dao, swaggerAddr string) Handler {
	return &restHandler{
		dao:         dao,
		swaggerHost: swaggerAddr,
	}
}

// swagger 项目描述
//	@title			排行榜
//	@version		1.0
//	@description	项目结构概要描述
//	@termsOfService	http://swagger.io/terms/

//	@tag.name			Hello
//	@tag.description	示例

//	@tag.name			Rank
//	@tag.description	排行榜

//	@contact.name	sinuxlee
//	@contact.url	http://www.swagger.io/support
//	@contact.email	sinuxlee@qq.com

//	@license.name	Apache 2.0
//	@license.url	http://www.apache.org/licenses/LICENSE-2.0.html

//	@schemes					http https
//	@host						localhost:8080
//	@BasePath					/svr
//	@query.collection.format	multi

//	@securityDefinitions.basic	BasicAuth

//	@securityDefinitions.apikey	TokenAuth
//	@in							header
//	@name						Authorization

//	@x-extension-openapi	{"example": "value on a json format"}

type restHandler struct {
	dao         store.Dao
	swaggerHost string
	svrName     string
}

// respData ...
func (r *restHandler) respData(ctx *gin.Context, data interface{}) {
	r.resp(ctx, &schema.Response{
		Code:    0,
		Message: "OK",
		Data:    data,
	})
}

// respCode ...
func (r *restHandler) respCode(ctx *gin.Context, code int32) {
	resp := &schema.Response{Code: code}
	desc, ok := status.Text[code]
	if ok {
		resp.Message = desc
	} else {
		resp.Message = "unknown error"
	}

	r.resp(ctx, resp)
}

// respDesc ...
func (r *restHandler) respDesc(ctx *gin.Context, code int32, desc string) {
	r.resp(ctx, &schema.Response{
		Code:    code,
		Message: desc,
	})
}

func (r *restHandler) resp(ctx *gin.Context, resp *schema.Response) {
	ctx.Header("X-Robot-Index", ctx.GetHeader("X-Robot-Index"))
	ctx.JSON(http.StatusOK, resp)
	if resp.Code != status.Success {
		r.ErrorLog(ctx, resp)
	}
}

func (r *restHandler) ErrorLog(ctx *gin.Context, resp *schema.Response) {
	log.Error().Str("path", ctx.Request.URL.Path).
		Str("query", ctx.Request.URL.RawQuery).
		Interface("response", resp).
		Msg("bad response")
}

func (r *restHandler) swaggerDocs(engine *gin.Engine) {
	docs.SwaggerInfo.Host = r.swaggerHost
	url := ginSwagger.URL(fmt.Sprintf("http://%v/swagger/doc.json", r.swaggerHost))
	engine.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler, url))
}

func (r *restHandler) healthCheck(engine *gin.Engine) {
	engine.GET("/healthz", func(ctx *gin.Context) {
		ctx.String(http.StatusOK, "It is OK\n")
	})
}

func (r *restHandler) static(engine *gin.Engine) error {
	relPath := fmt.Sprintf("%v/backend", r.svrName)
	engine.Use(func(c *gin.Context) {
		if strings.Contains(c.Request.RequestURI, relPath) {
			c.Header("Cache-Control", "private, max-age=3600")
		}
	})
	engine.StaticFS(relPath, http.FS(assets.Static))
	return nil
}

func (r *restHandler) Init(svrName string) error {
	r.svrName = svrName
	return nil
}

func (r *restHandler) RegisterHandler(engine *gin.Engine) error {
	r.healthCheck(engine)
	r.swaggerDocs(engine)
	if err := r.static(engine); err != nil {
		return err
	}

	svr := engine.Group(fmt.Sprintf("%v/v1", r.svrName))
	svr.Use(middleware.Logger())
	svr.GET("hello/:name", r.Hello)
	svr.POST("hello/:name", r.Hello)

	rank := svr.Group("/rank")
	rank.GET("/ranking/:pid", r.ranking) // 获取玩家名次
	rank.POST("/notice", r.notice)       // 更新玩家数据
	rank.GET("/part-rank/:pid", r.partRank)

	admin := svr.Group("/admin")
	admin.GET("/rank/list", r.list) // 分页查看所有玩家
	admin.POST("/rank/ban", r.ban)  // 拉黑某个玩家

	return nil
}
